// OGoMojo
// Whitemice.MOGI.MOGIMon
// License: LGPL
// Copyright: Whitemice Consulting, 2006
// Author(s): Adam Tauno Williams (awilliam@whitemice.org)
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Net;
using Whitemice.MOGI;

namespace Whitemice.MOGI.MOGIMon
{
	/// \brief Class that does the actually pushing of events to other subsystems
	public class Worker
	{
		IServer 		server;
		RecordKeeper 	keeper;
		ArrayList		pushers;
		
		/// \brief Constructor
		/// \param server Reference to the OpenGroupware server
		/// \param keeper Reference to the book keeper class
		public Worker(IServer server, RecordKeeper keeper)
		{
			this.server = server;
			this.keeper = keeper;
			pushers = null;
		}
		
		public void Load()
		{
			if (!(pushers == null))
				Shutdown();
			pushers = new ArrayList();
			LoadPushersFromAssemblies();
		}
		
		/// \brief Processes a change
		/// \param change Change to processes
		/// \note Pusher plugins are executed in the order in which there were loaded.
		/// There is no mechanism for determining the order of execution.  Each plugin
		/// should be entirely a stand alone processor.  The audit id of the change is
		/// sent to the book keeper once it has been processed by all the plugins.
		public void Do(Change change)
		{
			if (change == null)
			{
				keeper.Log.Fatal("Do recieved a NULL change!");
				throw new Exception("Do recieved a NULL change!");
			}
			if (change.DocumentName == null)
			{
				keeper.Log.Fatal("Do recieved a change for a NULL document!");
				throw new Exception("Do recieved a change for a NULL document!");			
			}
			if (pushers == null)
			{
				keeper.Log.Fatal("Pushers array is NULL!");
				throw new Exception("Pushers array is NULL!");
			}			
			keeper.Log.Debug("Working change:" 
				+ change.AuditEntry.ToString() 
				+ " to " 
				+ change.DocumentName);
			foreach(IPusher pusher in pushers)
			{
				if (pusher == null)
				{
					keeper.Log.Debug("Null pusher discovered in pushers array.");
					throw new Exception("Null pusher discovered in pushers array.");
				}
				switch(change.ChangeType)
				{
					case ChangeType.Create:
						server.Log.Debug("ChangeType is Create for " + change.DocumentName);
						pusher.Create(change.DocumentName, change.InterestedParties);
						break;
					case ChangeType.Update:
						server.Log.Debug("ChangeType is Update for " + change.DocumentName);
						pusher.Update(change.DocumentName, change.InterestedParties);
						break;
					case ChangeType.Delete:
						server.Log.Debug("ChangeType is Delete for " + change.DocumentName);
						pusher.Delete(change.DocumentName, change.InterestedParties);
						break;
				} // End switch(change.ChangeType)
			} // End foreach(IPusher pusher in pushers)
			keeper.PutProcessedEntry(change.AuditEntry);
		}
		
		/// \brief Shutdown
		/// \note This method loops through all the pusher plugins and executes
		/// thier Shutdown() method.  Once this method has been called Do() 
		/// should not be called again.
		public void Shutdown()
		{
			foreach(IPusher pusher in pushers)
				pusher.Shutdown();
		}
		
		/// \brief LoadPushers
		/// \note Checks the directory specified by MOGIMon.PusherDirectory and
		/// loads all the classes that implement IPusher.  It then calls that 
		/// classes Initialize method to start them up and provide a reference to
		/// the OpenGroupware server.
		protected void LoadPushersFromAssemblies()
		{
			// Load list of DLLs from PusherDirectory
			string[] assemblyFilenames = 
				Directory.GetFiles(
					server.GetDirectiveValue("MOGIMon","PusherDirectory"),
					@"*.dll");
			// Iterate list of DLLs
			foreach(string assemblyFilename in assemblyFilenames)
			{
				// Load DLL
				keeper.Log.Debug("Checking " + assemblyFilename + " for pushers...");
				Assembly assembly = Assembly.LoadFile(assemblyFilename);
				// Get list of types from DLL
				Type[] assemblyTypes = assembly.GetExportedTypes();
				// Iterate over types
				foreach(Type assemblyType in assemblyTypes)
				{
					// Is type an IPusher?
					if (assemblyType.GetInterface("IPusher") != null)
					{
						IPusher pusher;
						
						keeper.Log.Debug("Loading Pusher: " + assemblyType.FullName);
						// Marshal object
                  		pusher = (IPusher)Activator.CreateInstance(
                  			assemblyType, 
                  			new object[0]);
                  		// Initialize object
                  		pusher.Initialize(server);
                  		// Store object in pusher array
                  		pushers.Add(pusher);
					}
				}
			}
		} // End LoadPushers
	}
}